home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / pwdutils.00 / pwdutils / pwdutils-1.00 / passwd.c < prev    next >
C/C++ Source or Header  |  1996-05-16  |  17KB  |  726 lines

  1. /*
  2. ** Copyright 1996 Thorsten Kukuk <kukuk@uni-paderborn.de>
  3. **
  4. ** This program is free software; you can redistribute it and/or modify
  5. ** it under the terms of the GNU General Public License as published by
  6. ** the Free Software Foundation; either version 2 of the License, or
  7. ** (at your option) any later version.
  8. **
  9. ** This program is distributed in the hope that it will be useful,
  10. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ** GNU General Public License for more details.
  13. **
  14. ** You should have received a copy of the GNU General Public License
  15. ** along with this program; if not, write to the Free Software
  16. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. #include <pwd.h>
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <unistd.h>
  23. #include <string.h>
  24. #include <getopt.h>
  25. #include <malloc.h>
  26. #include <sys/stat.h>
  27. #include <sys/types.h>
  28.  
  29. #include "pwdutils.h"
  30. #include "version.h"
  31.  
  32. #define USER_NONE 0
  33. #define USER_LOCAL 1
  34. #define USER_NIS 2
  35. #define USER_BOTH 3
  36. #define MAX_LENGTH 1024
  37.  
  38. extern int __yp_check(char **);
  39. extern struct passwd * __nis_getpwnam(const char *, void *);
  40.  
  41. static int whereis_user(const char *);
  42. static int local_writeback(struct passwd *, char *);
  43. static int check_gecos (char *, char *);
  44. static void query_gecos_info (struct passwd *, struct npwd *);
  45.  
  46. char *progname;
  47.  
  48. static struct option chsh_options[] = {
  49.   { "local-user",  no_argument,       0, 'l' },
  50.   { "nis-user",    no_argument,       0, 'y' },
  51.   { "shell",       required_argument, 0, 's' },
  52.   { "list-shells", no_argument,       0, '\255' },
  53.   { "help",        no_argument,       0, 'u' },
  54.   { "usage",       no_argument,       0, 'u' },
  55.   { "version",     no_argument,       0, 'v' },
  56.   { NULL,          no_argument,       0, '0' },
  57. };
  58.  
  59. static char *chsh_str = "lys:uv";
  60.  
  61. static struct option chfn_options[] = {
  62.   { "local-user",   no_argument,       0, 'l' },
  63.   { "nis-user",     no_argument,       0, 'y' },
  64.   { "full-name",    required_argument, 0, 'f' },
  65.   { "office",       required_argument, 0, 'o' },
  66.   { "office-phone", required_argument, 0, 'p' },
  67.   { "home-phone",   required_argument, 0, 'h' },
  68.   { "help",         no_argument,       0, 'u' },
  69.   { "usage",        no_argument,       0, 'u' },
  70.   { "version",      no_argument,       0, 'v' },
  71.   { NULL,           no_argument,       0, '0' },
  72. };
  73.  
  74. static char *chfn_str = "lyf:o:p:h:uv";
  75.  
  76. static struct option passwd_options[] = {
  77.   { "local-user",   no_argument,       0, 'l' },
  78.   { "nis-user",     no_argument,       0, 'y' },
  79.   { "shell",        no_argument,       0, 's' },
  80.   { "list-shells",  no_argument,       0, '\255' },
  81.   { "full-name",    no_argument,       0, 'f' },
  82.   { "help",         no_argument,       0, 'u' },
  83.   { "usage",        no_argument,       0, 'u' },
  84.   { "version",      no_argument,       0, 'v' },
  85.   { NULL,           no_argument,       0, '0' },
  86. };
  87.  
  88. static char *passwd_str = "lysfuv";
  89.  
  90. static void Usage(const char* progname)
  91. {
  92.   if(strstr(progname,"passwd"))
  93.     {
  94.       printf("Usage: passwd [-l|-y] [-s|-f] [--list-shells] [-u] [-v] [user]\n");
  95.       exit(1);
  96.     }
  97.   if(strstr(progname,"chsh"))
  98.     {
  99.       printf("Usage: chsh [-l|-y] [-s shell] [--list-shells] [-u] [-v] [user]\n");
  100.       exit(1);
  101.     }
  102.  
  103.   if(strstr(progname,"chfn"))
  104.     {
  105.       printf("Usage: chfn [-l|-y] [-f full-name] [-o office] [-p office-phone] [-h home-phone] [-v] [user]\n");
  106.       exit(1);
  107.     }
  108.   fprintf(stderr, "%s: What should I do? Call me passwd, chsh or chfn!\n",
  109.       progname);
  110.   exit(1);
  111. }
  112.  
  113. int main(int argc, char *argv[])
  114. {
  115.   struct passwd *pwd = NULL;
  116.   struct option *long_options;
  117.   struct npwd newf;
  118.   uid_t gotuid = getuid();
  119.   char *user, *opt_str;
  120.   char *master = NULL;
  121.   char *oldpassword = NULL;
  122.   int c, index;
  123.   int use_yp = 0;
  124.   int use_local = 0;
  125.   int query_passwd = 1;
  126.   int query_shell = 0;
  127.   int query_gecos = 0;
  128.   int result = 0;
  129.   
  130.   memset (&newf, 0, sizeof (newf));
  131.  
  132.   progname = argv[0];
  133.  
  134.   if (strstr(argv[0],"yppasswd"))
  135.     {
  136.       use_yp = 1;
  137.       long_options = passwd_options;
  138.       opt_str = passwd_str;
  139.     }
  140.   else
  141.     if(strstr(argv[0],"ypchsh"))
  142.       {
  143.     use_yp = 1;
  144.     long_options = chsh_options;
  145.     opt_str = chsh_str;
  146.     query_passwd = 0;
  147.     query_shell = 1;
  148.       }
  149.     else
  150.       if(strstr(argv[0],"chsh"))
  151.     {
  152.       long_options = chsh_options;
  153.       opt_str = chsh_str;
  154.       query_passwd = 0;
  155.       query_shell = 1;
  156.     }
  157.       else
  158.     if(strstr(argv[0],"ypchfn"))
  159.       {
  160.         use_yp = 1;
  161.         long_options = chfn_options;
  162.         opt_str = chfn_str;
  163.         query_passwd = 0;
  164.         query_shell = 0;
  165.         query_gecos = 1;
  166.       }
  167.     else
  168.       if(strstr(argv[0],"chfn"))
  169.         {
  170.           long_options = chfn_options;
  171.           opt_str = chfn_str;
  172.           query_passwd = 0;
  173.           query_shell = 0;
  174.           query_gecos = 1;
  175.         }
  176.       else
  177.         {
  178.           long_options = passwd_options;
  179.           opt_str = passwd_str;
  180.         }
  181.  
  182.   while((c = getopt_long(argc, argv, opt_str, long_options, &index))!= EOF)
  183.     {
  184.       switch(c)
  185.     {
  186.     case '\255':
  187.       print_shell_list(NULL);
  188.       exit(0);
  189.       break;
  190.     case 'l':
  191.       if(use_yp)
  192.         {
  193.           fprintf(stderr,"You could only change a NIS entry or ");
  194.           fprintf(stderr,"a local entry!\n");
  195.           exit(1);
  196.         }
  197.       use_local = 1;
  198.       break;
  199.     case 'y':
  200.       if(use_local)
  201.         {
  202.           fprintf(stderr,"You could only change a local entry or ");
  203.           fprintf(stderr,"a NIS entry!\n");
  204.           exit(1);
  205.         }
  206.       use_yp = 1;
  207.       break;
  208.     case 's':
  209.       if(query_gecos)
  210.         {
  211.           fprintf(stderr,"You could not specify -s and -f at the same time.\n");
  212.           Usage(argv[0]);
  213.         }
  214.       query_passwd = 0;
  215.       query_shell = 1;
  216.       if (optarg) 
  217.         {
  218.           newf.shell = optarg;
  219.           /* root can set any shell he wish */
  220.           if(gotuid)
  221.         if(!check_shell(optarg))
  222.           return 1;
  223.         }
  224.       break;
  225.     case 'f':
  226.       if(query_shell)
  227.         {
  228.           fprintf(stderr,"You could not specify -s and -f at the same time.\n");
  229.           Usage(argv[0]);
  230.         }
  231.       query_passwd = 0;
  232.       query_gecos = 1;
  233.       if(optarg)
  234.         {
  235.           if(check_gecos("full name", optarg))
  236.         newf.full_name = optarg;
  237.         }
  238.       break;
  239.     case 'o':
  240.       if(check_gecos("office", optarg))
  241.         newf.office = optarg;
  242.       break;
  243.     case 'p':
  244.       if(check_gecos("office phone", optarg))
  245.         newf.office_phone = optarg;
  246.       break;
  247.     case 'h':
  248.       if(check_gecos("home phone", optarg))
  249.         newf.home_phone = optarg;
  250.       break;
  251.     case 'v':
  252.       printf("pwdutils %s\n", version);
  253.       exit (0);
  254.       break;
  255.     case 'u':
  256.     default:
  257.       Usage(argv[0]);
  258.       exit(0);
  259.       break;
  260.     }
  261.     }
  262.  
  263.   argc-=optind;
  264.   argv+=optind;
  265.  
  266.   umask (022);
  267.  
  268.   if(argc > 1) 
  269.     Usage(argv[0]);
  270.   else 
  271.     if(argc == 1) 
  272.       {
  273.         if(gotuid) 
  274.           {
  275.         if(query_passwd)
  276.           fprintf(stderr,"Only root can change the password for others\n");
  277.         else
  278.           if(query_shell)
  279.         fprintf(stderr,"Only root can change the shell for others\n");
  280.           else
  281.         fprintf(stderr,"Only root can change the gecos fields for others\n");
  282.             exit(1);
  283.           }
  284.         user = argv[0];
  285.       } 
  286.     else 
  287.       {
  288.         if (!(user = getlogin())) 
  289.           {
  290.             if (NULL==(pwd=getpwuid(getuid()))) 
  291.               {
  292.                 perror("Cannot find login name");
  293.                 exit(1);
  294.               } 
  295.             else
  296.               user = pwd->pw_name;
  297.           }
  298.       }
  299.   if(!(pwd = getpwnam(user))) 
  300.     {
  301.       fprintf(stderr,"Can't find username anywhere. Are you really a user?\n");
  302.       exit(1);
  303.     }
  304.   
  305.   /* if somebody got into changing utmp... */
  306.   if(gotuid && gotuid != pwd->pw_uid) 
  307.     {
  308.       puts("UID and username does not match, imposter!");
  309.       exit(1);
  310.     }
  311.  
  312.   switch(whereis_user(user))
  313.     {
  314.     case USER_LOCAL:
  315.       if(use_yp)
  316.     {
  317.       fprintf(stderr,"%s is a local user, not a NIS.\n",user);
  318.       exit(1);
  319.     }
  320. LOCAL_USER:
  321.       pwd = getpwnam(user);
  322.       break;
  323.     case USER_NIS:
  324.       if(use_local)
  325.     {
  326.       fprintf(stderr,"%s is a NIS user, not a local.\n",user);
  327.       exit(1);
  328.     }
  329.       else
  330.     use_yp = 1;
  331.  
  332. NIS_USER:
  333.       if(__yp_check(NULL) == 1)
  334.     {
  335.       static void *info_nis = NULL;
  336.       
  337.       if (NULL == info_nis)
  338.         {
  339.           info_nis = __pwdalloc();
  340.           if (NULL == info_nis)
  341.         {
  342.           fprintf(stderr,"ERROR: __pwdalloc failed.\n");
  343.           exit(1);
  344.         }
  345.           pwd = __nis_getpwnam(user, info_nis);
  346.           if(pwd == NULL)
  347.         {
  348.           fprintf(stderr,"ERROR: Could not read NIS entry for %s\n",user);
  349.           exit(1);
  350.         }
  351.         }
  352.     }
  353.       else
  354.     {
  355.       fprintf(stderr,"ERROR: NIS not running anymore ?\n");
  356.       exit(1);
  357.     }
  358.       break;
  359.     case USER_BOTH:
  360.       if(use_yp) 
  361.     goto NIS_USER;
  362.       else
  363.     {
  364.       use_local = 1;
  365.       goto LOCAL_USER;
  366.     }
  367.       break;
  368.     case USER_NONE:
  369.     default:
  370.       fprintf(stderr,"%s does not exist ?\n",user);
  371.       exit(1);
  372.     }
  373.  
  374. #ifdef DEBUG
  375.   printf("name.....: [%s]\n",pwd->pw_name);
  376.   printf("password.: [%s]\n",pwd->pw_passwd);
  377.   printf("user id..: [%d]\n",pwd->pw_uid);
  378.   printf("group id.: [%d]\n",pwd->pw_gid);
  379.   printf("gecos....: [%s]\n",pwd->pw_gecos);
  380.   printf("directory: [%s]\n",pwd->pw_dir);
  381.   printf("shell....: [%s]\n",pwd->pw_shell);
  382. #endif
  383.  
  384.   if (use_yp && (master = get_master_server()) == NULL) 
  385.     {
  386.       exit(1);
  387.     }
  388.  
  389.   if(query_passwd)
  390.     {
  391.       if(use_yp)
  392.     printf("Changing NIS password for %s on %s\n",pwd->pw_name,master);
  393.       else
  394.     printf("Changing password for %s\n",pwd->pw_name );
  395.       
  396.       if(use_yp && pwd->pw_passwd && pwd->pw_passwd[0]) 
  397.     oldpassword = getoldpwd(pwd);
  398.       
  399.       pwd->pw_passwd = getnewpwd(pwd);
  400.  
  401.       if(use_yp)
  402.     {
  403.       result = yp_writeback(pwd,oldpassword,master);
  404.       if(result)
  405.         fprintf( stderr, "Error while changing NIS password.\n");
  406.       printf("NIS password has%s been changed on %s.\n",
  407.          result? " *NOT*" : "", master);
  408.     }
  409.       else
  410.     {
  411.       result = local_writeback(pwd,"Password");
  412.       printf("Password has%s been changed.\n",
  413.          result? " *NOT*" : "");    
  414.     }
  415.     }
  416.  
  417.   if(query_shell)
  418.     {
  419.       if(use_yp)
  420.     printf("Changing login shell for %s on %s\n",pwd->pw_name,master);
  421.       else
  422.     printf("Changing login shell for %s\n",pwd->pw_name);
  423.  
  424.       
  425.       if(use_yp && pwd->pw_passwd && pwd->pw_passwd[0]) 
  426.     oldpassword = getoldpwd(pwd);
  427.  
  428.       if(!newf.shell)
  429.     newf.shell = prompt ("New shell", pwd->pw_shell);
  430.  
  431.       if ((newf.shell == NULL) || (strcmp (pwd->pw_shell, newf.shell)==0))
  432.     {
  433.       printf ("Shell not changed.\n");
  434.       return 0;
  435.     }
  436.       
  437.       if(gotuid)
  438.     if (!check_shell(newf.shell)) 
  439.       return 1;
  440.   
  441.       pwd->pw_shell = newf.shell;
  442.       
  443.       if(use_yp)
  444.     {
  445.       result = yp_writeback(pwd,oldpassword,master);
  446.       if(result)
  447.         fprintf( stderr, "Error while changing login shell.\n");
  448.       printf("Login shell has%s been changed on %s.\n",
  449.          result? " *NOT*" : "", master);
  450.     }
  451.       else
  452.     {
  453.       result = local_writeback(pwd,"Shell");
  454.       printf("Login shell has%s been changed.\n",
  455.          result? " *NOT*" : "");    
  456.     }
  457.     }
  458.  
  459.   if(query_gecos)
  460.     {
  461.       if(use_yp)
  462.     printf("Changing finger information for %s on %s\n",pwd->pw_name,master);
  463.       else
  464.     printf("Changing finger information for %s\n",pwd->pw_name);
  465.  
  466.       
  467.       if(use_yp && pwd->pw_passwd && pwd->pw_passwd[0]) 
  468.       oldpassword = getoldpwd(pwd);
  469.  
  470.       parse_passwd(pwd, &newf);
  471.       
  472.       if(!newf.full_name && !newf.office && !newf.office_phone &&
  473.      !newf.home_phone)
  474.     query_gecos_info(pwd, &newf);
  475.       
  476.       if (! set_changed_finger_data(pwd, &newf)) 
  477.     {
  478.       printf ("Finger information not changed.\n");
  479.       return 0;
  480.     }
  481.       
  482.       if(use_yp)
  483.     {
  484.       result = yp_writeback(pwd,oldpassword,master);
  485.       if(result)
  486.         fprintf( stderr, "Error while changing finger information.\n");
  487.       printf("Finger information has%s been changed on %s.\n",
  488.          result? " *NOT*" : "", master);
  489.     }
  490.       else
  491.     {
  492.       result = local_writeback(pwd,"Finger information");
  493.       printf("Finger information has%s been changed.\n",
  494.          result? " *NOT*" : "");    
  495.     }
  496.     }
  497.  
  498.   return result;
  499. }
  500.  
  501. /*
  502. ** whereis_user - looks, if the user is local, NIS, both or none of them
  503. */
  504. static int whereis_user(const char *user)
  505. {
  506.   FILE *file;
  507.   int result;
  508.   struct passwd *pwd = NULL;
  509.   char line[MAX_LENGTH];
  510.  
  511.   result = USER_NONE;
  512.  
  513.   if((file = fopen("/etc/passwd","r"))==NULL)
  514.     {
  515.       fprintf(stderr,"ERROR: Can't open /etc/passwd\n");
  516.       exit(1);
  517.     }
  518.  
  519.   while(fgets(line, MAX_LENGTH, file) != NULL)
  520.     {
  521.       int userlen = strlen(user);
  522.  
  523.       if((strncmp(user,line,userlen) == 0) && 
  524.      (line[userlen] == ':'))
  525.     {
  526.       result+=USER_LOCAL;
  527.       break;
  528.     }
  529.     }
  530.   fclose(file);
  531.  
  532.   if(__yp_check(NULL) == 1)
  533.     {
  534.       static void *info_nis = NULL;
  535.       
  536.       if (NULL == info_nis)
  537.     {
  538.       info_nis = __pwdalloc();
  539.       if (NULL == info_nis)
  540.         return result;
  541.     }
  542.       pwd = __nis_getpwnam(user, info_nis);
  543.       if(pwd == NULL)
  544.     return result;
  545.  
  546.       result+=USER_NIS;
  547.     }
  548.  
  549.   return result;
  550. }
  551.  
  552. /*
  553. ** local_writeback - returns 1 for a error, else 0
  554. ** At first, we locks the passwd file, then we copy it and
  555. ** change a passwd entry. "info" is, what we are changing
  556. ** (Password, Shell or Finger Information)
  557. */
  558. static int local_writeback(struct passwd *pwd, char *info)
  559. {
  560.   FILE *from, *to;
  561.   int done;
  562.   char *cptr, buf[8192];
  563.   
  564.   pwd_init();
  565.   if(lckpwdf() != 0)
  566.     {
  567.       fprintf(stderr,"Can't lock /etc/passwd! Try again later.\n");
  568.       return 1;
  569.     }
  570.   
  571.   if (!(from = fopen("/etc/passwd", "r"))) 
  572.     pwd_error("Couldn't open /etc/passwd",info);
  573.   
  574.   if (!(to = fopen("/etc/passwd.tmp", "w"))) 
  575.     {
  576.       fclose(from);
  577.       pwd_error("Couldn't open /etc/passwd.tmp",info);
  578.     }
  579.   chmod("/etc/passwd.tmp",S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  580.   
  581.   for (done = 0; fgets(buf, sizeof(buf), from);) 
  582.     {
  583.       if (!strchr(buf, '\n')) 
  584.         {
  585.           fclose(from);
  586.           fclose(to);
  587.           pwd_error("/etc/passwd: line too long",info);
  588.         }
  589.       
  590.       if (done) 
  591.         {
  592.           fprintf(to, "%s", buf);
  593.           if (ferror(to))
  594.             {
  595.               fclose(to);
  596.               fclose(from);
  597.               pwd_error("unknown error by writing",info);
  598.             }
  599.           continue;
  600.         }
  601.       
  602.       if (!(cptr = strchr(buf, ':'))) 
  603.         {
  604.           fclose(to);
  605.           fclose(from);
  606.           pwd_error("/etc/passwd: corrupted entry",info);
  607.         }
  608.       
  609.       *cptr = '\0';
  610.       if (strcmp(buf, pwd->pw_name)) 
  611.         {
  612.           *cptr = ':';
  613.           fprintf(to, "%s", buf);
  614.           if (ferror(to))
  615.             {
  616.               fclose(to);
  617.               fclose(from);
  618.               pwd_error("unknown error by writing",info);
  619.             }
  620.           continue;
  621.         }
  622.       
  623.       fprintf(to, "%s:%s:%d:%d:%s:%s:%s\n",
  624.               pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid,
  625.               pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
  626.       done = 1;
  627.       if (ferror(to))
  628.         {
  629.           fclose(to);
  630.           fclose(from);
  631.           pwd_error("unknown error by writing",info);
  632.         }
  633.     }
  634.   if (!done) 
  635.     {
  636.       fclose(to);
  637.       fclose(from);
  638.       fprintf(stderr,"user \"%s\" not found in /etc/passwd -- \
  639. NIS maps and password file possibly out of sync", pwd->pw_name);
  640.       ulckpwdf();
  641.       return 1;
  642.     }
  643.  
  644.   if (ferror(to)) 
  645.     {
  646.       fclose(to);
  647.       fclose(from);
  648.       pwd_error("unknown error by writing",info);
  649.     }
  650.   
  651.   fclose(to);
  652.   fclose(from);
  653.   unlink("/etc/passwd");
  654.   rename("/etc/passwd.tmp","/etc/passwd");
  655.  
  656.   ulckpwdf();
  657.   return 0;
  658. }
  659.  
  660. /*
  661. **  query_gecos_info - prompt the user for the finger information
  662. */
  663. static void query_gecos_info (struct passwd *pwd, struct npwd *newf)
  664. {
  665.   printf("Changing finger information for %s.\n", pwd->pw_name);
  666.   newf->full_name = prompt("Name", newf->old_full_name);
  667.   while(!check_gecos("full name",newf->full_name))
  668.     {
  669.       printf("Try again\n");
  670.       free(newf->full_name);
  671.       newf->full_name = prompt("Name", newf->old_full_name);
  672.     }
  673.   newf->office = prompt("Office", newf->old_office);
  674.   while(!check_gecos("office", newf->office))
  675.     {
  676.       printf("Try again\n");
  677.       free(newf->office);
  678.       newf->office = prompt("Office",newf->old_office);
  679.     }
  680.   newf->office_phone = prompt ("Office Phone", newf->old_office_phone);
  681.   while(!check_gecos("office phone", newf->office_phone))
  682.     {
  683.       printf("Try again\n");
  684.       free(newf->office_phone);
  685.       newf->office_phone = prompt("Office Phone",newf->old_office_phone);
  686.     }
  687.   newf->home_phone = prompt ("Home Phone", newf->old_home_phone);
  688.   while(!check_gecos("home phone", newf->home_phone))
  689.     {
  690.       printf("Try again\n");
  691.       free(newf->home_phone);
  692.       newf->office = prompt("Home Phone",newf->home_phone);
  693.     }
  694. }
  695.  
  696. /*
  697. ** check of the given gecos string is legal.  If not,
  698. ** print "msg" followed by a description of the problem, and
  699. ** return 0. If it is legal, return 1
  700. */
  701. static int check_gecos (char *msg, char *gecos)
  702. {
  703.   unsigned int i;
  704.   char *c;
  705.   
  706.   if((c=strpbrk(gecos,",:=\"\n")) != NULL)
  707.     {
  708.       if(msg) 
  709.     printf("%s: ", msg);
  710.       printf("Invalid characters in gecos argument: '%c' is not allowed.\n",c[0]);
  711.       return 0;
  712.     }
  713.  
  714.   for(i = 0; i < strlen(gecos); i++)
  715.     {
  716.       if(iscntrl(gecos[i])) 
  717.     {
  718.       if(msg) 
  719.         printf("%s: ", msg);
  720.       printf ("Control characters are not allowed.\n");
  721.       return 0;
  722.     }
  723.     }
  724.   return 1;
  725. }
  726.